package com.xdf.ecommerce.controller;

import com.alibaba.fastjson.JSON;
import com.xdf.ecommerce.constant.CommonConstant;
import com.xdf.ecommerce.service.NacosClientService;
import com.xdf.ecommerce.service.hystrix.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import rx.Observable;
import rx.Observer;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

/**
 * @author chanchaw
 * @create 2025-10-29 16:52
 */
@Slf4j
@CrossOrigin
@RestController
@RequestMapping("/hystrix")
@RequiredArgsConstructor
public class HystrixController {
    private final CacheHystrixCommandAnnotation cacheAnno;
    private final NacosClientService nacosClientService;
    private final UseHystrixCommandAnnotation useHystrixCommandAnnotation;
    @PostMapping("/testHystrix")
    public List<ServiceInstance> test(){
        List<ServiceInstance> nacosClientInfo = useHystrixCommandAnnotation.getNacosClientInfo(CommonConstant.AUTHORITY_CENTER_SERVICE_ID);
        return nacosClientInfo;
    }
    @PostMapping("/program")
    public List<ServiceInstance> programHystrixCommand() throws ExecutionException, InterruptedException {
        String serviceId = CommonConstant.AUTHORITY_CENTER_SERVICE_ID;

        // 第一种，同步阻塞的方式
        NacosClientHystrixCommand nacosClientHystrixCommand = new NacosClientHystrixCommand(nacosClientService, serviceId);
        List<ServiceInstance> retList01 = nacosClientHystrixCommand.execute();

        // 第二种，异步非阻塞的方式
        NacosClientHystrixCommand hystrixCommand = new NacosClientHystrixCommand(nacosClientService, serviceId);
        Future<List<ServiceInstance>> future = hystrixCommand.queue();
        /** 异步执行过程中，这里可以做其他任务 **/
        List<ServiceInstance> retList02 = future.get();

        // 第三种方式，类似前端的 Promise（异步热响应）
        Observable<List<ServiceInstance>> observable = new NacosClientHystrixCommand(nacosClientService, serviceId).observe();// 声明一个异步任务，并不会立即执行
        List<ServiceInstance> retList03 = observable.toBlocking().single();// 执行异步任务并获取数据

        // 第四种方式，异步冷响应方式
        Observable<List<ServiceInstance>> toObservable = new NacosClientHystrixCommand(nacosClientService, serviceId).toObservable();
        List<ServiceInstance> retList04 = toObservable.toBlocking().single();

        return retList01;
    }
    /**
     * 测试信号量方式实现舱壁隔离，服务降级
     * @return
     * @throws ExecutionException
     * @throws InterruptedException
     */
    @PostMapping("/hystrixSamp")
    public List<ServiceInstance> hystrixSamp() throws ExecutionException, InterruptedException {
        ArrayList<String> serviceIds = new ArrayList<>();
        serviceIds.add(CommonConstant.AUTHORITY_CENTER_SERVICE_ID);
        NacosClientHystrixObservableCommand hystrixObs = new NacosClientHystrixObservableCommand(nacosClientService, serviceIds);
        Observable<List<ServiceInstance>> observe = hystrixObs.observe();

        List<ServiceInstance> ret = new ArrayList<>(serviceIds.size());
        observe.subscribe(
                new Observer<List<ServiceInstance>>() {
                    @Override
                    public void onCompleted() {
                        log.info("信号量方式 Hystrix 保护的服务[查询获取服务实例]执行完毕，线程名称：[{}]", Thread.currentThread().getName());
                    }

                    @Override
                    public void onError(Throwable throwable) {
                        throwable.printStackTrace();
                        log.info("信号量方式 Hystrix 保护的服务[查询获取服务实例]执行完毕，出现错误：[{}]", throwable.toString());
                    }

                    @Override
                    public void onNext(List<ServiceInstance> serviceInstances) {
                        log.info("信号量方式 Hystrix 保护的服务[查询获取服务实例]开始执行，线程名称：[{}]", Thread.currentThread().getName());
                        ret.addAll(serviceInstances);
                    }
                }
        );
        return ret;
    }

    /**
     * Hystrix 的请求缓存的整个生命周期在一次请求中，当一次请求中有重复的方法执行，则会使用缓存的结果
     * 即，该缓存仅存在于一次请求内部，多个请求间不存在缓存数据
     *
     * 在第一个 log.info 之前创建两个实例，执行两次，第一次执行 CacheHystrixCommand.run 中的逻辑后会缓存结果
     * 第二次执行时会从缓存中获取结果，即不会打印 CacheHystrixCommand.run 中的日志内容
     *
     * 之后通过调用 flushCache 清理缓存后再次执行，则应该会再次出现打印 CacheHystrixCommand.run 中的日志内容
     * 即本请求中执行三次查询服务实例，只有两次相同的日志，中间依次执行不会打印日志就对了
     */
    @PostMapping("/cacheHystrixCommand")
    public void cacheHystrixCommand(){
        String serviceId = CommonConstant.AUTHORITY_CENTER_SERVICE_ID;
        CacheHystrixCommand c1 = new CacheHystrixCommand(nacosClientService, serviceId);
        CacheHystrixCommand c2 = new CacheHystrixCommand(nacosClientService, serviceId);
        List<ServiceInstance> r1 = c1.execute();
        List<ServiceInstance> r2 = c2.execute();

        log.info("一个请求内两次执行的结果：[{}],[{}]", JSON.toJSONString(r1), JSON.toJSONString(r2));

        CacheHystrixCommand.flushCache(serviceId);
        CacheHystrixCommand c3 = new CacheHystrixCommand(nacosClientService, serviceId);
        List<ServiceInstance> r3 = c3.execute();
        log.info("清理缓存后又一次执行的结果：[{}]", JSON.toJSONString(r3));
    }

    /**
     * 测试 Hystrix 请求缓存的注解实现方式
     */
    @PostMapping("/cacheHystrixCommandAnnotation")
    public void cacheHystrixCommandAnnotation(){
        String serviceId = CommonConstant.AUTHORITY_CENTER_SERVICE_ID;
        List<ServiceInstance> t1 = cacheAnno.useCacheByAnnotation02(serviceId);
        log.info("使用第二种请求缓存的方法请求服务 [{}] 响应来的结果是：[{}]", serviceId, JSON.toJSONString(t1));

        List<ServiceInstance> t2 = cacheAnno.useCacheByAnnotation02(serviceId);
        log.info("第二次请求，应该从缓存中获取数据，在本日志之前不应该出现初次请求的日志内容");

        cacheAnno.flushCacheByAnnotation02(serviceId);
        List<ServiceInstance> t3 = cacheAnno.useCacheByAnnotation02(serviceId);
        log.info("清除缓存后再次请求，在本日志之前应该有初次请求的日志内容");
    }
}
